using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Globalization;
using FreeLancer.HRB.Core.Services;
using System.Configuration;

namespace FreeLancer.HRB.Core
{
  /// <summary>
  /// Represents the configured settings for the web core.
  /// </summary>
  public class WebAppSettings
  {
    #region Private/Protected/Public Members

    /// <summary>
    /// Web settings changed
    /// </summary>
    public static event EventHandler<EventArgs> Changed;
    private static WebAppSettings webSettingsSingleton;
    private string configuredTheme = String.Empty;
    private int numberOfRecentPosts = 10;
    

    #endregion

    #region WebAppSettings()
		/// <summary>
    /// Initializes a new instance of the <see cref="WebAppSettings"/> class.
		/// </summary>
    private WebAppSettings()
		{
			//------------------------------------------------------------
			//	Attempt to initialize class state
			//------------------------------------------------------------
			//try
			//{
			//------------------------------------------------------------
			//	Load the currently configured settings
			//------------------------------------------------------------
			Load();
			//}
			//catch
			//{
			//    //------------------------------------------------------------
			//    //	Rethrow exception
			//    //------------------------------------------------------------
			//    throw;
			//}
		}
		#endregion

    //============================================================
    //	STATIC PROPERTIES
    //============================================================
    #region Instance
    /// <summary>
    /// Gets the singleton instance of the <see cref="WebAppSettings"/> class.
    /// </summary>
    /// <value>A singleton instance of the <see cref="WebAppSettings"/> class.</value>
    /// <remarks></remarks>
    public static WebAppSettings Instance
    {
      get
      {
        if (webSettingsSingleton == null)
        {
          webSettingsSingleton = new WebAppSettings();
        }
        return webSettingsSingleton;
      }
    }
    #endregion

    //============================================================
    //	GENERAL SETTINGS
    //============================================================

    #region AlternateFeedUrl
    private string _alternateFeedUrl;
    /// <summary>Gets or sets the FeedBurner user name.</summary>
    public string AlternateFeedUrl
    {
      get { return _alternateFeedUrl; }
      set { _alternateFeedUrl = value; }
    }
    #endregion

    #region TrackingScript
    private string _trackingScript;
    /// <summary>
    /// Gets or sets the tracking script used to collect visitor data.
    /// </summary>
    public string TrackingScript 
    { 
      get { return _trackingScript; } 
      set { _trackingScript = value; } 
    }
    #endregion

    #region HtmlHeader
    private string _htmlHeader;
    /// <summary>
    /// Gets or sets the name of the author of this blog.
    /// </summary>
    /// <value>The name of the author of this blog.</value>
    public string HtmlHeader
    {
      get { return _htmlHeader; }
      set { _htmlHeader = value; }
    }
    #endregion

    #region Culture
    private string _culture;
    /// <summary>
    /// Gets or sets the culture.
    /// </summary>
    /// <value>The name of culture.</value>
    public string Culture
    {
      get { return _culture; }
      set { _culture = value; }
    }
    #endregion

    #region AdministratorRole
    /// <summary>
    /// The role that has administrator persmissions
    /// </summary>
    public string AdministratorRole
    {
      get { return ConfigurationManager.AppSettings["WebApp.AdminRole"] ?? "administrators"; }
    }
    #endregion

    #region Name
    private string _name;
    /// <summary>
    /// Gets or sets the name of the blog.
    /// </summary>
    /// <value>The title of the blog.</value>
    public string Name 
    { 
      get { return _name; } 
      set { _name = value; } 
    }
    #endregion

    #region EnableHttpCompression
    private bool _enableHttpCompression;
    /// <summary>
    /// Gets or sets a value indicating if HTTP compression is enabled.
    /// </summary>
    /// <value><b>true</b> if compression is enabled, otherwise returns <b>false</b>.</value>
    public bool EnableHttpCompression
    {
      get
      {
        return _enableHttpCompression;
      }
      set
      {
        _enableHttpCompression = value;
      }
    }

    #endregion

    #region EnableReferrerTracking
    private bool _enableReferrerTracking;
    /// <summary>
    /// Gets or sets a value indicating if referral tracking is enabled.
    /// </summary>
    /// <value><b>true</b> if referral tracking is enabled, otherwise returns <b>false</b>.</value>
    public bool EnableReferrerTracking 
    { 
      get { return _enableReferrerTracking; } 
      set { _enableReferrerTracking = value;} 
    }
    #endregion

    #region CompressWebResource
    private bool _compressWebResource;
    /// <summary>
    /// Gets or sets a value indicating whether to compress WebResource.axd
    /// </summary>
    /// <value><c>true</c> if [compress web resource]; otherwise, <c>false</c>.</value>
    public bool CompressWebResource 
    { 
      get { return _compressWebResource; } 
      set { _compressWebResource = value;} 
    }
    #endregion

    #region StorageLocation
    private string _storageLocation;
    /// <summary>
    /// Gets or sets the default storage location for blog data.
    /// </summary>
    /// <value>The default storage location for blog data.</value>
    public string StorageLocation 
    { 
      get { return _storageLocation; } 
      set { _storageLocation = value; } 
    }
    #endregion

    #region TimeStampPostLinks
    private bool _timeStampPostLinks;
    /// <summary>Gets or sets whether or not to time stamp post links.</summary>
    public bool TimeStampPostLinks 
    { 
      get { return _timeStampPostLinks; } 
      set { _timeStampPostLinks = value; } 
    }
    #endregion

    #region FileExtension
    /// <summary>
    /// The  file extension used for aspx pages
    /// </summary>
    public string FileExtension
    {
      get { return ConfigurationManager.AppSettings["WebApp.FileExtension"] ?? ".aspx"; }
    }
    #endregion

    #region Timezone
    private double _timezone;
    /// <summary>
    /// Gets or sets the maximum number of characters that are displayed from a blog-roll retrieved post.
    /// </summary>
    /// <value>The maximum number of characters to display.</value>
    public double Timezone 
    { 
      get { return _timezone; } 
      set { _timezone = value; } 
    }
    #endregion

    #region HandleWwwSubdomain
    private string _handleWwwSubdomain;
    /// <summary>
    /// Gets or sets how to handle the www subdomain of the url (for SEO purposes).
    /// </summary>
    public string HandleWwwSubdomain 
    { 
      get { return _handleWwwSubdomain; }  
      set { _handleWwwSubdomain = value; } 
    }
    #endregion

    //============================================================
    //	EMAIL SETTINGS
    //============================================================

    #region Email
    private string _email;
    /// <summary>
    /// Gets or sets the e-mail address notifications are sent to.
    /// </summary>
    /// <value>The e-mail address notifications are sent to.</value>
    public string Email 
    { 
      get { return _email; }
      set { _email = value; }
    }
    #endregion

    #region SendMailOnComment
    private bool _sendMailOnComment;
    /// <summary>
    /// Gets or sets a value indicating if an enail is sent when a comment is added to a post.
    /// </summary>
    /// <value><b>true</b> if email notification of new comments is enabled, otherwise returns <b>false</b>.</value>
    public bool SendMailOnComment 
    {
      get { return _sendMailOnComment; }
      set { _sendMailOnComment = value; }
    }

    #endregion

    #region SmtpPassword
    private string _smtpPassword;
    /// <summary>
    /// Gets or sets the password used to connect to the SMTP server.
    /// </summary>
    /// <value>The password used to connect to the SMTP server.</value>
    public string SmtpPassword 
    {
      get { return _smtpPassword; }
      set { _smtpPassword = value; }
    }
    #endregion

    #region SmtpServer
    private string _smtpServer;
    /// <summary>
    /// Gets or sets the DNS name or IP address of the SMTP server used to send notification emails.
    /// </summary>
    /// <value>The DNS name or IP address of the SMTP server used to send notification emails.</value>
    public string SmtpServer 
    {
      get { return _smtpServer; }
      set { _smtpServer = value; }
    }
    #endregion

    #region SmtpServerPort
    private int _smtpServerPort;
    /// <summary>
    /// Gets or sets the DNS name or IP address of the SMTP server used to send notification emails.
    /// </summary>
    /// <value>The DNS name or IP address of the SMTP server used to send notification emails.</value>
    public int SmtpServerPort
    {
      get { return _smtpServerPort; }
      set { _smtpServerPort = value; }
    }
    #endregion

    #region SmtpUsername
    private string _smtpUserName;
    /// <summary>
    /// Gets or sets the user name used to connect to the SMTP server.
    /// </summary>
    /// <value>The user name used to connect to the SMTP server.</value>
    public string SmtpUserName {
      get { return _smtpUserName; }
      set { _smtpUserName = value; }
    }
    #endregion

    #region EnableSsl
    private bool _enableSsl;
    /// <summary>
    /// Gets or sets a value indicating if SSL is enabled for sending e-mails
    /// </summary>
    public bool EnableSsl {
      get { return _enableSsl; }
      set { _enableSsl = value; }
    }
    #endregion

    #region EmailSubjectPrefix
    private string _emailSubjectPrefix;
    /// <summary>
    /// Gets or sets the email subject prefix.
    /// </summary>
    /// <value>The email subject prefix.</value>
    public string EmailSubjectPrefix {
      get { return _emailSubjectPrefix; }
      set { _emailSubjectPrefix = value; }
    }
    #endregion

    //============================================================
    //	PRIVATE ROUTINES
    //============================================================
    #region Load()
    /// <summary>
    /// Initializes the singleton instance of the <see cref="WebAppSettings"/> class.
    /// </summary>
    private void Load()
    {
      Type settingsType = this.GetType();

      //------------------------------------------------------------
      //	Enumerate through individual settings nodes
      //------------------------------------------------------------
      System.Collections.Specialized.StringDictionary dic = CoreService.LoadSettings();

      foreach (string key in dic.Keys)
      {
        //------------------------------------------------------------
        //	Extract the setting's name/value pair
        //------------------------------------------------------------
        string name = key;
        string value = dic[key];

        //------------------------------------------------------------
        //	Enumerate through public properties of this instance
        //------------------------------------------------------------
        foreach (PropertyInfo propertyInformation in settingsType.GetProperties())
        {
          //------------------------------------------------------------
          //	Determine if configured setting matches current setting based on name
          //------------------------------------------------------------
          if (propertyInformation.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
          {
            //------------------------------------------------------------
            //	Attempt to apply configured setting
            //------------------------------------------------------------
            try
            {
              if (propertyInformation.CanWrite)
              {
                propertyInformation.SetValue(this, Convert.ChangeType(value, propertyInformation.PropertyType, CultureInfo.CurrentCulture), null);
              }
            }
            catch
            {
              // TODO: Log exception to a common logging framework?
            }
            break;
          }
        }
      }
      StorageLocation = GetStorageLocation();
    }
    #endregion

    #region OnChanged()
    /// <summary>
    /// Occurs when the settings have been changed.
    /// </summary>
    private static void OnChanged()
    {
      //------------------------------------------------------------
      //	Attempt to raise the Changed event
      //------------------------------------------------------------
      try
      {
        //------------------------------------------------------------
        //	Execute event handler
        //------------------------------------------------------------
        if (WebAppSettings.Changed != null)
        {
          WebAppSettings.Changed(null, new EventArgs());
        }
      }
      catch
      {
        //------------------------------------------------------------
        //	Rethrow exception
        //------------------------------------------------------------
        throw;
      }
    }
    #endregion

    //============================================================
    //	PUBLIC ROUTINES
    //============================================================
    #region Save()
    /// <summary>
    /// Saves the settings to disk.
    /// </summary>
    public void Save()
    {
      System.Collections.Specialized.StringDictionary dic = new System.Collections.Specialized.StringDictionary();
      Type settingsType = this.GetType();

      //------------------------------------------------------------
      //	Enumerate through settings properties
      //------------------------------------------------------------
      foreach (PropertyInfo propertyInformation in settingsType.GetProperties())
      {
        try
        {
          if (propertyInformation.Name != "Instance")
          {
            //------------------------------------------------------------
            //	Extract property value and its string representation
            //------------------------------------------------------------
            object propertyValue = propertyInformation.GetValue(this, null);
            string valueAsString = propertyValue.ToString();

            //------------------------------------------------------------
            //	Format null/default property values as empty strings
            //------------------------------------------------------------
            if (propertyValue.Equals(null))
            {
              valueAsString = String.Empty;
            }
            if (propertyValue.Equals(Int32.MinValue))
            {
              valueAsString = String.Empty;
            }
            if (propertyValue.Equals(Single.MinValue))
            {
              valueAsString = String.Empty;
            }

            //------------------------------------------------------------
            //	Write property name/value pair
            //------------------------------------------------------------
            dic.Add(propertyInformation.Name, valueAsString);
          }
        }
        catch { }
      }

      CoreService.SaveSettings(dic);
      OnChanged();
    }
    #endregion

    #region Version()

    private static string _Version;
    /// <summary>
    /// Returns the BlogEngine.NET version information.
    /// </summary>
    /// <value>The BlogEngine.NET major, minor, revision, and build numbers.</value>
    /// <remarks>The current version is determined by extracting the build version of the BlogEngine.Core assembly.</remarks>
    public string Version()
    {
      if (_Version == null)
        _Version = GetType().Assembly.GetName().Version.ToString();

      return _Version;
    }
    #endregion

    //============================================================
    //	PUBLIC ROUTINES
    //============================================================

    #region GetStorageLocation()

    private string GetStorageLocation()
    {
      if (String.IsNullOrEmpty(System.Web.Configuration.WebConfigurationManager.AppSettings["StorageLocation"]))
        return @"~/App_Data/";
      return System.Web.Configuration.WebConfigurationManager.AppSettings["StorageLocation"];
    }

    #endregion
  }
}
